package service;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import model.Device;
import exceptions.ConnectionNotFoundException;
import exceptions.GenericSQLException;

/**
 * Session Bean implementation class DeviceService
 */
@Stateless(mappedName = "deviceService")
@LocalBean
public class DeviceService {

    /**
     * Default constructor.
     */
    public DeviceService() {
    }

    /**
     * Vraag op of het device al geregistreerd is in de database
     *
     * @param device Het device
     * @return Het id van het device indien geregistreerd, anders -1.
     */
    public int isRegistered(Device device) {

        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet result = null;

        try {

            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/HRODevicesPool");
            conn = ds.getConnection();

            String query = "select id from device where deviceid = ?";
            preparedStatement = conn.prepareStatement(query);
            preparedStatement.setString(1, device.getDeviceId());
            result = preparedStatement.executeQuery();

            if (result.next()) {
                return result.getInt(1);
            }
            else {
                return -1;
            }
        }
        catch (NamingException e) {

            e.printStackTrace();

            throw new ConnectionNotFoundException("De databaseverbinding kan niet worden opgevraagd");
        }
        catch (SQLException e) {

            e.printStackTrace();

            throw new GenericSQLException("Er gaat iets mis met opvragen van het device uit de database.");
        }
        finally {

            try {

                if (result != null) {
                    result.close();
                }
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Registreer het device in de database en geef het id terug.
     *
     * @param device Het device dat geregistreerd moet worden.
     * @return Het id van het geregistreerde device.
     */
    public int registerDivice(Device device) {

        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet generatedKeys = null;

        try {

            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/HRODevicesPool");
            conn = ds.getConnection();

            String query = "insert into device (deviceid) values (?)";
            preparedStatement = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
            preparedStatement.setString(1, device.getDeviceId());
            int affectedRows = preparedStatement.executeUpdate();

            if (affectedRows != 1) {
                throw new GenericSQLException("Er gaat iets mis met het opslaan van het device in de database.");
            }

            generatedKeys = preparedStatement.getGeneratedKeys();
            if (generatedKeys.next()) {

                return generatedKeys.getInt(1);
            }
            else {
                throw new GenericSQLException("Er gaat iets mis met het opslaan van het device in de database.");
            }
        }
        catch (NamingException e) {

            e.printStackTrace();

            throw new ConnectionNotFoundException("De databaseverbinding kan niet worden opgevraagd");
        }
        catch (SQLException e) {

            e.printStackTrace();

            throw new GenericSQLException("Er gaat iets mis met het opslaan van het device in de database.");
        }
        finally {

            try {

                if (generatedKeys != null) {
                    generatedKeys.close();
                }
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Wis de registratie van het device in de database.
     *
     * @param device Het device waarvan de registratie moet worden verwijderd.
     */
    public void unRegisterDevice(Device device) {

        Connection conn = null;
        PreparedStatement preparedStatement = null;

        try {

            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/HRODevicesPool");
            conn = ds.getConnection();

            String query = "delete from device where deviceid = ?";
            preparedStatement = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
            preparedStatement.setString(1, device.getDeviceId());
            int affectedRows = preparedStatement.executeUpdate();

            if (affectedRows != 1) {
                throw new GenericSQLException("Er gaat iets mis met het verwijderen van het device in de database.");
            }
        }
        catch (NamingException e) {

            e.printStackTrace();

            throw new ConnectionNotFoundException("De databaseverbinding kan niet worden opgevraagd");
        }
        catch (SQLException e) {

            e.printStackTrace();

            throw new GenericSQLException("Er gaat iets mis met het verwijderen van het device in de database.");
        }
        finally {

            try {

                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Registreer de meegegeven les in het meegegeven device.
     *
     * @param deviceId Het device waarvoor de les geregistreerd moet worden.
     * @param teacherId De teacher die voor het meegegeven device geregistreerd moet worden.
     */
    public void registerLessonForDevice(int deviceId, int teacherId) {

        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet generatedKeys = null;

        try {

            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/HRODevicesPool");
            conn = ds.getConnection();

            String query = "insert into device_has_teacher (device_id, teacher_id) values (?, ?)";
            preparedStatement = conn.prepareStatement(query);
            preparedStatement.setInt(1, deviceId);
            preparedStatement.setInt(2, teacherId);
            int affectedRows = preparedStatement.executeUpdate();

            if (affectedRows != 1) {
                throw new GenericSQLException("Er gaat iets mis met het opslaan van de teachers voor device: " + deviceId);
            }
        }
        catch (NamingException e) {

            e.printStackTrace();

            throw new ConnectionNotFoundException("De databaseverbinding kan niet worden opgevraagd");
        }
        catch (SQLException e) {

            e.printStackTrace();

            throw new GenericSQLException("Er gaat iets mis met het opslaan van de teachers voor device: " + deviceId);
        }
        finally {

            try {

                if (generatedKeys != null) {
                    generatedKeys.close();
                }
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Wis de registratie van alle teachers voor het meegegeven device.
     *
     * @param deviceId Het device waarvan alle les registraties moeten worden gewist.
     */
    public void unregisterLessonsForDevice(int deviceId) {

        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet generatedKeys = null;

        try {

            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/HRODevicesPool");
            conn = ds.getConnection();

            String query = "delete from device_has_teacher where device_id = ?";
            preparedStatement = conn.prepareStatement(query);
            preparedStatement.setInt(1, deviceId);
            preparedStatement.executeUpdate();
        }
        catch (NamingException e) {

            e.printStackTrace();

            throw new ConnectionNotFoundException("De databaseverbinding kan niet worden opgevraagd");
        }
        catch (SQLException e) {

            e.printStackTrace();

            throw new GenericSQLException("Er gaat iets mis met wissen van de teachers voor device: " + deviceId);
        }
        finally {

            try {

                if (generatedKeys != null) {
                    generatedKeys.close();
                }
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Vraag alle devices voor de meegegeven teacher op.
     *
     * @param code De docentcode waarvan alle devices moeten worden verwijderd.
     * @return Een lijst met daarin alle devices voor de meegegeven teacher.
     */
    public ArrayList<String> getDevicesByTeacher(String code) {

        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet result = null;

        try {

            ArrayList<String> devices = new ArrayList<String>();

            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/HRODevicesPool");
            conn = ds.getConnection();

            String query = "select deviceid from teacher left join device_has_teacher on teacher.id = device_has_teacher.teacher_id left join device on device_has_teacher.device_id = device.id where teacher.code = ?";
            preparedStatement = conn.prepareStatement(query);
            preparedStatement.setString(1, code);
            result = preparedStatement.executeQuery();

            while (result.next()) {
                devices.add(result.getString("deviceid"));
            }

            return devices;
        }
        catch (NamingException e) {

            e.printStackTrace();

            throw new ConnectionNotFoundException("De databaseverbinding kan niet worden opgevraagd");
        }
        catch (SQLException e) {

            e.printStackTrace();

            throw new GenericSQLException("Er gaat iets mis met opvragen van de devices uit de database.");
        }
        finally {

            try {

                if (result != null) {
                    result.close();
                }
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (conn != null) {
                    conn.close();
                }
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
